package com.vf.admin.client.controller.oldPay.wechat.controller;

import com.alibaba.fastjson.JSON;
import com.vf.admin.client.common.ClientConstants;
import com.vf.admin.client.common.RedisKeys;
import com.vf.admin.client.service.pay.WxPayService;
import com.vf.admin.client.service.*;
import com.vf.admin.client.controller.oldPay.wechat.utils.WxPayV3Config;
import com.vf.admin.common.BaseController;
import com.vf.admin.common.Constants;
import com.vf.admin.common.entity.Result;
import com.vf.admin.common.redis.RedisUtil;
import com.vf.admin.fiwork.controller.AppDailyTasController;
import com.vf.admin.miaodong.entity.*;
import com.vf.admin.utils.pay.ApiAplayWeChat.IpUtils;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.*;
import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.util.Date;
import java.util.Map;

import static com.vf.admin.common.Constants.dingdan_status_dfk;
import static com.vf.admin.common.Constants.dingdan_zhiFuLeiXing_wx;
import static com.vf.admin.utils.RandomUtil.getOrderIdByUUId;

/**
 * <p>Title : 微信支付</p>
 * <p>Description : </p>
 * <p>DevelopTools : IDEA</p>
 * <p>DevelopSystem : Windows10</p>
 *
 * @Author : NemoMeng
 * @Date 2023/6/21 10:16
 */
@Controller
@CrossOrigin
@RequestMapping(value = "/api/wechat")
public class WeChatPayController extends BaseController {

    private Logger logger = LoggerFactory.getLogger(getClass());
    @Autowired
    AppUserService appUserService;
    @Autowired
    private AppSetupService appSetupService;
    @Autowired
    private AppOrderService appOrderService;
    @Autowired
    private AppMingXiZuanShiService appMingXiZuanShiService;
    @Autowired
    private AppMingxiChongzhiService appMingxiChongzhiService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private AppDailyTasController appDailyTasController;
    @Autowired
    private AppInvitationRecordService appInvitationRecordService;
    @Autowired
    private AgentUserService agentUserService;
    @Autowired
    private VipOrderService vipOrderService;
    @Autowired
    WxPayService wxPayService;
    @Autowired
    AppPrivilegeService appPrivilegeService;
    @Autowired
    AppCzMoneyService appCzMoneyService;


    /**
     * 如果你是使用Apache HttpClient的商户开发者，可以使用它构造HttpClient。得到的HttpClient在执行请求时将自动携带身份认证信息，并检查应答的微信支付签名。
     */
    private static CloseableHttpClient httpClient = null;

    /**
     * 初始化
     */
    public static void setup() throws UnsupportedEncodingException {
        // 加载商户私钥（privateKey：私钥字符串）
        PrivateKey merchantPrivateKey = PemUtil
                .loadPrivateKey(new ByteArrayInputStream(WxPayV3Config.private_key.getBytes("utf-8")));

        // 加载平台证书（mchId：商户号,mchSerialNo：商户证书序列号,apiV3Key：V3密钥）
        AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
                new WechatPay2Credentials(WxPayV3Config.mch_id, new PrivateKeySigner(WxPayV3Config.mchSerialNo, merchantPrivateKey)), WxPayV3Config.apiV3Key.getBytes("utf-8"));

        // 初始化httpClient
        httpClient = WechatPayHttpClientBuilder.create()
                .withMerchant(WxPayV3Config.mch_id, WxPayV3Config.mchSerialNo, merchantPrivateKey)
                .withValidator(new WechatPay2Validator(verifier)).build();
    }

    /**
     * h5统一下单
     */
    /**
     * 钻石充值H5
     *
     * @param request
     * @param productId 产品ID
     * @return
     */
    @RequestMapping(value = "/diamondRechargeWeb")
    @ResponseBody
    public Result diamondRechargeWeChatWeb(HttpServletRequest request, Integer productId) {

        try {
            setup();
            AppSetup setup = appSetupService.get();
            if (setup.getOpenRecharge() == 0) {
                return this.errorJSON(setup.getRechargeTip());
            }
            AppCzMoney appCzMoney = appCzMoneyService.get(productId);
            String orderNo = getOrderIdByUUId();
            //添加订单记录
            AppOrder topup = new AppOrder();
            topup.setCreatetime(new Date());
            topup.setOrdernum(orderNo);//生成订单号
            topup.setCzMoneyId(productId);
            topup.setMoney(new BigDecimal(appCzMoney.getMoney()));
            topup.setStatus(Constants.dingdan_status_dfk);//默认 1、代付款
            topup.setType(dingdan_zhiFuLeiXing_wx);//支付类型 2、微信支付
            //下单人信息
            AppUser user = appUserService.get((Integer) redisUtil.get(RedisKeys.userToken + request.getHeader(ClientConstants.client_toke)));
            topup.setUserid(user.getId());
            topup.setPic(user.getPic());
            topup.setNick(user.getNick());
            topup.setPhone(user.getLoginname());
            topup.setNum(appCzMoney.getDiamonds().add(appCzMoney.getGive()));
            appOrderService.save(topup);

//        int total = topup.getMoney().multiply(new BigDecimal(100)).intValue();//单位是分
            int total = 1;//单位是分

            //获取ip地址
            String ipAddr = IpUtils.getRealIp(request);

            //请求URL
            HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/h5");

            // 请求body参数
            String reqdata = "{"
                    + "\"amount\": {"
                    + "\"total\": " + total + ","
                    + "\"currency\": \"CNY\""
                    + "},"
                    + "\"scene_info\": {"
                    + "\"payer_client_ip\":\"" + ipAddr + "\","
                    + "\"h5_info\": {"
                    + "\"type\": \"Android\"" + "}},"
                    + "\"mchid\": \"" + WxPayV3Config.mch_id + "\","
                    + "\"description\":\"钻石充值\","
                    + "\"notify_url\": \"" + WxPayV3Config.notify_url + "\","
                    + "\"out_trade_no\": \"" + orderNo + "\","
                    + "\"appid\": \"" + WxPayV3Config.app_id + "\"" + "}";

            StringEntity entity = new StringEntity(reqdata, "utf-8");
            entity.setContentType("application/json");
            httpPost.setEntity(entity);
            httpPost.setHeader("Accept", "application/json");

            //完成签名并执行请求
            CloseableHttpResponse response = httpClient.execute(httpPost);
            String signMap = "";
            try {
                int statusCode = response.getStatusLine().getStatusCode();
                if (statusCode == 200) {
                    signMap = EntityUtils.toString(response.getEntity());
                } else if (statusCode == 204) {
                    System.out.println("success");
                } else {
                    System.out.println("failed,resp code = " + statusCode + ",return body = " + EntityUtils.toString(response.getEntity()));
                    throw new IOException("request failed");
                }
            } finally {
                response.close();
            }
            return this.sucessJSON(signMap, "成功");
        } catch (Exception e) {

            e.printStackTrace();
            return this.errorJSON("服务器繁忙，请您稍后重试!");
        }
    }

    /**
     * 微信支付回调
     */
    @RequestMapping(value = "/wxNotify", method = RequestMethod.POST)
    @ResponseBody
    public void h5PayNotifyUrl(HttpServletRequest request) throws Exception {

        //获取报文
        String body = getRequestBody(request);
        //证书序列号
        String serialNumber = request.getHeader("Wechatpay-Serial");
        //随机串
        String Nonce = request.getHeader("Wechatpay-Nonce");
        //时间戳
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        //微信传递过来的签名
        String signature = request.getHeader("Wechatpay-Signature");

        //报文转map
        System.out.println("请求体=" + body);
        Map requestMap = (Map) JSON.parse(body);

        //获取resource
        String resource = String.valueOf(requestMap.get("resource"));
        System.out.println("resource=" + resource);
        Map requestMap2 = (Map) JSON.parse(resource);

        //获取associated_data   nonce   ciphertext
        String associated_data = (String) requestMap2.get("associated_data");
        String nonce = (String) requestMap2.get("nonce");
        String ciphertext = (String) requestMap2.get("ciphertext");

        //按照文档要求拼接验签串
        String VerifySignature = timestamp + "\n" + Nonce + "\n" + body + "\n";
        System.out.println("拼接后的验签串=" + VerifySignature);

        //使用官方验签工具进行验签
        Verifier verifier = verifier();
        boolean verify = verifier.verify(serialNumber, VerifySignature.getBytes(), signature);
        System.out.println("官方工具验签=" + verify);

        //验证成功执行数据操作
        if (verify) {
            System.out.println("验签成功后，开始进行解密");
            //解密，如果这里报错，就一定是APIv3密钥错误
            AesUtil aesUtil = new AesUtil(WxPayV3Config.apiV3Key.getBytes());
            String aes = aesUtil.decryptToString(associated_data.getBytes(), nonce.getBytes(), ciphertext);
            System.out.println("解密数据：" + aes);
            //判断
            Map map = (Map) JSON.parse(aes);
            String trade_state = (String) map.get("trade_state");
            String orderNum = (String) map.get("out_trade_no");
            if ("SUCCESS".equals(trade_state)) {

                AppOrder topup = appOrderService.getByOrdernum(orderNum, dingdan_zhiFuLeiXing_wx, dingdan_status_dfk);

                //判断预订单是否存在
                if (!StringUtils.isEmpty(topup)) {
                    //
                    AppUser user = appUserService.get(topup.getUserid());
                    //存在则更改预订单支付状态
                    appOrderService.updateStastusYzf(orderNum, 2);
                    //
                    BigDecimal getDiamond = topup.getNum();
                    //添加用户钻石金额
                    appUserService.updateZuanShi(user.getId(), getDiamond);
                    //增加用户累积充值金额
                    appUserService.updateLeijiChongzhi(user.getId(), topup.getMoney());
                    //添加钻石明细
                    appMingXiZuanShiService.addMingxi(user.getId(), getDiamond, 1, "充值");
                    //添加充值明细
                    appMingxiChongzhiService.addMingxi(user.getId(), getDiamond, 2, topup.getMoney(), orderNum,topup.getMobileSpec());
                    //完成充值任务
                    appDailyTasController.getAwardOnce(topup.getUserid(), ClientConstants.TaskOnce.RECHARGE_FIRST);
                    //如果有上级发放用户充值提成
                    addAward(topup);
                    //
                    agentUserService.shareMoneyRecharge(user.getId(), topup.getNum());
                    //升级贵族
                    appPrivilegeService.isUpLevel(user);
                }
            }
        }


    }

    public Verifier verifier() throws Exception {
        //获取证书管理器实例
        CertificatesManager certificatesManager = CertificatesManager.getInstance();
        // 向证书管理器增加需要自动更新平台证书的商户信息
        certificatesManager.putMerchant(WxPayV3Config.mch_id, new WechatPay2Credentials(WxPayV3Config.mch_id,
                        new PrivateKeySigner(WxPayV3Config.mchSerialNo, PemUtil.loadPrivateKey(WxPayV3Config.private_key)))
                , WxPayV3Config.apiV3Key.getBytes(StandardCharsets.UTF_8));
        Verifier verifier = certificatesManager.getVerifier(WxPayV3Config.mch_id);
        return verifier;
    }


    /**
     * 读取请求数据流
     *
     * @param request
     * @return
     */
    private String getRequestBody(HttpServletRequest request) {

        StringBuffer sb = new StringBuffer();

        try (ServletInputStream inputStream = request.getInputStream();
             BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        ) {
            String line;

            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }

        } catch (IOException e) {
            logger.error("读取数据流异常:{}", e);
        }

        return sb.toString();
    }

    /**
     * 邀请用户充值增加父级提成
     *
     * @param order
     */
    public void addAward(AppOrder order) {
        AppInvitationRecord record = appInvitationRecordService.getShangji(order.getUserid());
        if (record != null) {
            AppSetup appSetup = appSetupService.get();
            BigDecimal divide = order.getNum().multiply(appSetup.getRechargeInvite()).setScale(2, BigDecimal.ROUND_HALF_UP);
            appUserService.addDiamonds(record.getPuserid(), divide, "邀请用户充值提成");
        }
    }
}
